package org.zoomdev.zoom.common.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class OrderedList<E> {

    private final ArrayList<OrderInfo> list;


    public OrderedList() {
        list = new ArrayList<OrderInfo>();
    }

    public void add(E element, int order) {
        if (list.size() == 0) {
            list.add(new OrderInfo(element, order));
            return;
        }

        for (int i = list.size() - 1; i >= 0; --i) {
            OrderInfo old = list.get(i);
            if (order < old.order) {
                if (i == 0) {
                    list.add(0, new OrderInfo(element, order));
                    break;
                }
            } else {
                list.add(i + 1, new OrderInfo(element, order));
                break;
            }
        }

    }


    public E get(int i) {
        return list.get(i).element;
    }

    public void addAll(E... elements) {
        int max = getMaxOrder();
        for (E e : elements) {
            list.add(new OrderInfo(e, ++max));
        }
    }

    public int size() {
        return list.size();
    }

    public void clear() {
        list.clear();
    }

    public List<E> toList() {
        final List<OrderInfo> list = this.list;
        return Collections.unmodifiableList(CollectionUtils.map(list, new Converter<OrderInfo, E>() {
            @Override
            public E convert(OrderInfo data) {
                return data.element;
            }
        }));
    }

    public E[] toArray(E[] array) {
        assert (array != null && array.length == list.size());
        final List<OrderInfo> list = this.list;
        int c = list.size();

        for (int i = 0; i < c; ++i) {
            OrderInfo info = list.get(i);
            array[i] = info.element;
        }
        return array;
    }

    private int getMaxOrder() {
        final List<OrderInfo> list = this.list;
        if (list.size() == 0) {
            return 0;
        }
        int max = Integer.MIN_VALUE;
        for (OrderInfo orderInfo : list) {
            if (max < orderInfo.order) {
                max = orderInfo.order;
            }
        }
        return max;
    }

    private class OrderInfo {
        E element;
        int order;

        OrderInfo(E element, int order) {
            this.element = element;
            this.order = order;
        }
    }

}
